#include "tcpclient.h"
#include "ui_tcpclient.h"

#include <QDebug>
#include <QMessageBox>
#include <QHostAddress>
#include "protocol.h"
#include "operatewidget.h"
#include "privatechat.h"

TcpClient::TcpClient(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::TcpClient)
{
    ui->setupUi(this);
    this->loadConfig();
    resize(750, 450);

    connect(&m_tcpsocket, &QTcpSocket::connected, this, &TcpClient::show_connect);

    // OperateWidget::getInstance().get_book()->flush_file();  //刷新文件列表

    connect(&m_tcpsocket, &QTcpSocket::readyRead, this, [&]() {
        if (!OperateWidget::getInstance().get_book()->download_flag()) {
            //qDebug() << m_tcpsocket.bytesAvailable();
            uint total_len = 0;
            m_tcpsocket.read((char*)&total_len, sizeof(total_len));
            uint PDUmsg_len = total_len - sizeof(PDU);
            PDU* pdu = makePDU(PDUmsg_len);
            m_tcpsocket.read((char*)pdu+sizeof(uint), total_len - sizeof(uint));

            // qDebug() << "readRead";
            // pdu->printPDU();
            switch (pdu->uiMsgType) {
            case ENUM_MSG_TYPE_REGIST_RESPOND: {
                if (!strcmp(pdu->caData, REGIST_OK))
                    QMessageBox::information(this, "注册成功", "注册成功");
                else if (!strcmp(pdu->caData, REGIST_FAILED))
                    QMessageBox::critical(this, "注册失败", "注册失败");
                break;
            }
            case ENUM_MSG_TYPE_LOGIN_RESPOND: {
                if (!strcmp(pdu->caData, LOGIN_OK)) {
                    QMessageBox::information(this, "登陆成功", "登陆成功");
                    m_current_dir = QString("./%1").arg(m_login_name);
                    //显示图书和好友操作界面
                    OperateWidget::getInstance().show();
                    this->hide();
                } else if (!strcmp(pdu->caData, LOGIN_FAILED))
                    QMessageBox::critical(this, "登陆失败", "登陆失败");
                break;
            }
            case ENUM_MSG_TYPE_SHOW_ONLINE_RESPOND: {
                // pdu->printPDU();
                OperateWidget::getInstance().getFriend()->show_online_user(pdu);
                break;
            }
            case ENUM_MSG_TYPE_SEARCH_RESPOND: {
                QString name = OperateWidget::getInstance().getFriend()->search_name;
                if (!strcmp(pdu->caData, NO_THIS_PEOPLE)) {  //返回0 表示字符串相等
                    QMessageBox::information(this, "搜索",QString("%1 不存在").arg(name) );
                } else if (!strcmp(pdu->caData, PEOPLE_ONLINE)) {
                    QMessageBox::information(this, "搜索", QString("%1 在线").arg(name));
                } else {
                    QMessageBox::information(this, "搜索", QString("%1 不在线").arg(name));
                }
                break;
            }
            case ENUM_MSG_TYPE_ADD_FRIEND_REQUEST: { //添加好友请求
                char name[32] = {'\0'};
                strncpy(name, pdu->caData+32, 32);
                int ret = QMessageBox::information(this, "添加好友",
                                                   QString("%1 想添加你为好友").arg(name),
                                                   QMessageBox::Yes,
                                                   QMessageBox::No );
                if (ret == QMessageBox::Yes) {
                    pdu->uiMsgType = ENUM_MSG_TYPE_ADD_FRIEND_AGREE;
                    m_tcpsocket.write((char*)pdu, pdu->uiPDULen); //发送给服务器处理
                } /*else if (ret == QMessageBox::No) {
                pdu->uiMsgType = ENUM_MSG_TYPE_ADD_FRIEND_REFUSE;
            }*/

                break;
            }
            case ENUM_MSG_TYPE_ADD_FRIEND_RESPOND: { //不用添加好友(出错, 已经是好友...)
                QMessageBox::information(this, "添加好友失败", QString(pdu->caData) );
                break;
            }
            case ENUM_MSG_TYPE_FLUSH_FRIEND_RESPOND: {
                qDebug() << "client: ENUM_MSG_TYPE_FLUSH_FRIEND_RESPOND";
                OperateWidget::getInstance().getFriend()->show_online_friend(pdu);
                break;
            }
            case ENUM_MSG_TYPE_DEL_FRIEND_REQUEST: {
                char name[32] = {'\0'};
                strncpy(name, pdu->caData+32, 32);
                QMessageBox::information(this, "删除好友",
                                         QString("%1 删除了好友").arg(name));
                break;
            }
            case ENUM_MSG_TYPE_DEL_FRIEND_RESPOND: {
                QMessageBox::information(this, "删除好友成功", QString(pdu->caData) );
                break;
            }
            case ENUM_MSG_TYPE_SEND_MSG_REQUEST: {
                if (PrivateChat::getInstance().isHidden()) {
                    PrivateChat::getInstance().show();
                }
                PrivateChat::getInstance().set_name(pdu->caData);
                // qDebug() << pdu->caData;
                PrivateChat::getInstance().update_msg(pdu);
                break;
            }
            case ENUM_MSG_TYPE_GROUP_CHAT_REQUEST: {
                OperateWidget::getInstance().getFriend()->show_group_msg(pdu);
                break;
            }
            case ENUM_MSG_TYPE_CREATE_DIR_RESPOND: {
                QMessageBox::information(this, "创建文件夹", QString(pdu->caData) );
                OperateWidget::getInstance().get_book()->flush_file();  //刷新文件列表
                break;
            }
            case ENUM_MSG_TYPE_FLUSH_FILE_RESPOND: {
                if (!strcmp(pdu->caData, FLUSH_FILE_OK)) { //返回0 表示字符串相等
                    //如果刷新成功, 跟新当前目录
                    // m_current_dir = OperateWidget::getInstance().get_book()->get_str_enter_folder();
                    // qDebug() << m_current_dir;

                    QString curPath = OperateWidget::getInstance().get_book()->get_enter_dir();
                    // qDebug() << curPath;

                    if (!curPath.isEmpty()) {
                        m_current_dir = m_current_dir + "/" + curPath;
                        qDebug() << "enter dir:" << m_current_dir;
                    }

                    OperateWidget::getInstance().get_book()->show_file(pdu);
                }
                break;
            }
            case ENUM_MSG_TYPE_GO_BACK_DIR_RESPOND: {
                if (!strcmp(pdu->caData, FLUSH_FILE_OK)) { //返回0 表示字符串相等
                    //如果刷新成功, 跟新当前目录
                    // m_current_dir = OperateWidget::getInstance().get_book()->get_str_enter_folder();
                    // qDebug() << m_current_dir;

                    QString curPath = OperateWidget::getInstance().get_book()->get_go_back_dir();
                    qDebug() << "TcpClient.cpp:" <<  curPath;

                    if (!curPath.isEmpty()) {
                        m_current_dir = curPath;
                        //qDebug() << "go back dir:" << m_current_dir;
                    }
                    OperateWidget::getInstance().get_book()->show_file(pdu);
                } else {
                    OperateWidget::getInstance().get_book()->setGo_back_dir("");
                }
                break;
            }
            case ENUM_MSG_TYPE_DEL_FILE_RESPOND: {
                QMessageBox::information(this, "删除文件", QString(pdu->caData) );
                OperateWidget::getInstance().get_book()->flush_file();  //刷新文件列表
                break;
            }
            case ENUM_MSG_TYPE_RENAME_FILE_RESPOND: {
                QMessageBox::information(this, "重命名文件", QString(pdu->caData) );
                OperateWidget::getInstance().get_book()->flush_file();  //刷新文件列表
                break;
            }
            case ENUM_MSG_TYPE_ENTER_FOLDER_RESPOND: {  //进入文件夹失败
                OperateWidget::getInstance().get_book()->clear_enter_dir();
                QMessageBox::information(this, "进入文件夹", QString(pdu->caData) );
                break;
            }
            case ENUM_MSG_TYPE_UPLOAD_FILE_RESPOND: {
                QMessageBox::information(this, "上传文件", QString(pdu->caData) );
                OperateWidget::getInstance().get_book()->flush_file();  //刷新文件列表
                break;
            }
            case ENUM_MSG_TYPE_DOWNLOAD_FILE_RESPOND: {
                // pdu->printPDU();
                char file_name[32] = {'\0'};
                sscanf(pdu->caData, "%s %lld", file_name, &(OperateWidget::getInstance().get_book()->m_recv_total) );
                if (strlen(file_name) > 0 &&
                    OperateWidget::getInstance().get_book()->m_recv_total > 0) {
                    OperateWidget::getInstance().get_book()->setDownload_flag(true);
                    qDebug() << OperateWidget::getInstance().get_book()->save_path();
                    m_recv_file.setFileName(OperateWidget::getInstance().get_book()->save_path());
                    if (!m_recv_file.open(QIODevice::WriteOnly)) {
                        QMessageBox::warning(this, "打开文件", "下载文件时, 打开文件失败");
                    }

                }

                break;
            }
            case ENUM_MSG_TYPE_SHARE_FILE_RESPOND: {
                QMessageBox::information(this, "共享文件", QString(pdu->caData) );
                break;
            }
            case ENUM_MSG_TYPE_SHARE_FILE_NOTE: {
                char* path = new char[pdu->uiMsgLen];
                memcpy(path, pdu->caMsg, pdu->uiMsgLen);
                // /aa/bb/cc
                // qDebug() << "path = " << path;
                char *pos = strrchr(path, '/'); //strrchr从末尾开始找字符'/'
                if (pos) {
                    pos++; //pos[0] = '/'
                    QString note = QString("%1 share file->%2 \n 你想接收吗").arg(pdu->caData).arg(path);
                    // QMessageBox::question(this, "共享文件", "是否接收")
                    if (QMessageBox::question(this, "共享文件", note) == QMessageBox::Yes) {
                        PDU* req_pdu = makePDU(pdu->uiMsgLen);
                        req_pdu->uiMsgType = ENUM_MSG_TYPE_SHARE_FILE_NOTE_RESPOND;
                        memcpy(req_pdu->caMsg, pdu->caMsg, pdu->uiMsgLen);
                        QString name = TcpClient::getInstance().get_login_name();
                        strcpy(req_pdu->caData, name.toStdString().c_str());
                        m_tcpsocket.write((char*)req_pdu, req_pdu->uiPDULen);
                        // req_pdu->printPDU();
                        free(req_pdu); req_pdu = NULL;
                    }
                }
                break;
            }
            case ENUM_MSG_TYPE_MOVE_FILE_RESPOND: {
                QMessageBox::information(this, "移动文件", QString(pdu->caData) );
                OperateWidget::getInstance().get_book()->flush_file();  //刷新文件列表
                break;
            }
            default:
                break;
            }

            free(pdu); pdu = NULL;
        } else { //接收文件
            QByteArray buff = m_tcpsocket.readAll();
            m_recv_file.write(buff);
            Book* book = OperateWidget::getInstance().get_book();
            book->m_recved += buff.size();
            // qDebug() << "buff = " << buff.toStdString().c_str();
            if (book->m_recv_total == book->m_recved) { //数据接收完毕
                m_recv_file.close();
                book->m_recv_total = 0; book->m_recved = 0;
                OperateWidget::getInstance().get_book()->setDownload_flag(false);
                QMessageBox::information(this, "下载文件", "客户端接收文件成功");
            } else if (book->m_recv_total < book->m_recved) { //数据接收失败
                m_recv_file.close();
                book->m_recv_total = 0; book->m_recved = 0;
                OperateWidget::getInstance().get_book()->setDownload_flag(false);
                QMessageBox::warning(this, "下载文件", "客户端接收文件失败");
            }
        }

    });

    m_tcpsocket.connectToHost(QHostAddress(m_ip), m_port);
}

TcpClient::~TcpClient()
{
    delete ui;
}

void TcpClient::loadConfig()
{
    QFile file(":/client.config");
    if (file.open(QIODevice::ReadOnly)) {
        QByteArray ba_data = file.readAll();
        QString str_data = ba_data.toStdString().c_str();
        file.close();
        QStringList str_list = str_data.split("\n");
        m_ip = str_list[0];
        m_port = str_list[1].toUShort();
        // qDebug() << m_ip << "-" << m_port ;

    } else
        QMessageBox::critical(this, "open file", "open file failed");
}

void TcpClient::show_connect()
{
    QMessageBox::information(this, "socket 信号", "tcp socket 连接成功");
}

// void TcpClient::on_send_pushButton_clicked()
// {
//     // QString str = ui->send_lineEdit->text();
//     // // qDebug() << "client: sizeof(msg) = "<< sizeof(str);
//     // if (!str.isEmpty()) {
//     //     PDU* pdu = makePDU(str.size());
//     //     pdu->uiMsgType = 8888;
//     //     memcpy(pdu->caMsg, str.toStdString().c_str(), str.size());
//     //     m_tcpsocket.write((char*)pdu, pdu->uiPDULen);
//     //     pdu->printPDU();
//     //     free(pdu);
//     //     pdu = NULL;
//     // } else {
//     //     QMessageBox::information(this, "数据发送", "数据发送不能为空");
//     // }
// }

void TcpClient::on_login_btn_clicked()
{
    QString name = ui->username_let->text();
    QString pwd = ui->pwd_let->text();

#if 1 //测试时方便
    if (name == "" && pwd == "") {
        name = "jack"; pwd = "jack";
    }
#endif

    if (!name.isEmpty() && !pwd.isEmpty()) {
        m_login_name = name;
        PDU* pdu = makePDU(0); //注册的实际消息长度=0
        qDebug() << "sizeof(*pdu) = " << sizeof(pdu);
        qDebug() << "sizeof(PDU) = " << sizeof(PDU);
        pdu->uiMsgType = ENUM_MSG_TYPE_LOGIN_REQUEST;
        strncpy(pdu->caData, name.toStdString().c_str(), 32);
        strncpy(pdu->caData+32, pwd.toStdString().c_str(), 32);

        m_tcpsocket.write((char*)pdu, pdu->uiPDULen); //socket 发送
        // pdu->printPDU();
        free(pdu);
        pdu = NULL;
    } else {
        QMessageBox::information(this, "登陆失败", "用户名和密码都不能为空");
    }
}

void TcpClient::on_register_btn_clicked()
{
    QString name = ui->username_let->text();
    QString pwd = ui->pwd_let->text();
    if (!name.isEmpty() && !pwd.isEmpty()) {
        PDU* pdu = makePDU(0); //注册的实际消息长度=0
        pdu->uiMsgType = ENUM_MSG_TYPE_REGIST_REQUEST;
        strncpy(pdu->caData, name.toStdString().c_str(), 32);
        strncpy(pdu->caData+32, pwd.toStdString().c_str(), 32);

        m_tcpsocket.write((char*)pdu, pdu->uiPDULen); //socket 发送
        // pdu->printPDU();
        free(pdu);
        pdu = NULL;
    } else {
        QMessageBox::information(this, "注册失败", "用户名和密码都不能为空");
    }
}

void TcpClient::on_logout_btn_clicked()
{
    // QString name = ui->username_let->text();
    // if (!name.isEmpty()) {
    //     PDU* pdu = makePDU(0); //注册的实际消息长度=0
    //     pdu->uiMsgType = ENUM_MSG_TYPE_REGIST_REQUEST;
    //     strncpy(pdu->caData, name.toStdString().c_str(), 32);
    //     strncpy(pdu->caData+32, pwd.toStdString().c_str(), 32);

    //     m_tcpsocket.write((char*)pdu, pdu->uiPDULen); //socket 发送
    //     // pdu->printPDU();
    //     free(pdu);
    //     pdu = NULL;
    // } else {
    //     QMessageBox::information(this, "注册失败", "用户名和密码都不能为空");
    // }
}

TcpClient &TcpClient::getInstance()
{
    static TcpClient tcp;
    return tcp;
}

QTcpSocket &TcpClient::getTcpSocket()
{
    return m_tcpsocket;
}

QString TcpClient::get_login_name()
{
    return m_login_name;
}

QString TcpClient::get_current_dir()
{
    return m_current_dir;
}

void TcpClient::set_current_dir(const QString &path)
{
    m_current_dir = path;
}

